/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "sle_ssap_client_hal.h"
#include "sle_ssap_client_hdi.h"
#include "sle_hilog.h"
#include "sle_loader_hal.h"
#include <stdlib.h>
#include <stdio.h>

static SleSsapcHdiOpts *g_sleSsapcHalOpts = NULL;
static SleSsapcHdiCallbacks *g_sleSsapcHdiCbks = NULL;
static SleSsapcHalCallbacks *g_sleSsapcHalCbks = NULL;

static void OnSleHdiSsapcFindStructureCallback(uint8_t clientId, uint16_t connectId, const ClientFindServiceRes *service, SleHdiErrorCode errCode)
{
    SLE_LOGD("OnSleHdiSsapcFindStructureCallback errCode(0x%{public}08X)", errCode);
    if (g_sleSsapcHalCbks != NULL && g_sleSsapcHalCbks->OnSsapcStructFoundCb != NULL) {
        g_sleSsapcHalCbks->OnSsapcStructFoundCb(clientId, connectId, service, errCode);
    }
}

static void OnSleHdiSsapcFindPropertyCallback(uint8_t clientId, uint16_t connectId, const ClientFindPropertyRes *property, SleHdiErrorCode errCode)
{
    SLE_LOGD("OnSleHdiSsapcFindPropertyCallback errCode(0x%{public}08X)", errCode);
    if (g_sleSsapcHalCbks != NULL && g_sleSsapcHalCbks->OnSsapcPropertyFoundCb != NULL) {
        g_sleSsapcHalCbks->OnSsapcPropertyFoundCb(clientId, connectId, property, errCode);
    }
}

static void OnSleHdiSleHdiSsapcFindStructureCompleteCallback(uint8_t clientId, uint16_t connectId, const ClientFindStructureRes *structureResult, SleHdiErrorCode errCode)
{
    SLE_LOGI("OnSleHdiSleHdiSsapcFindStructureCompleteCallback errCode(0x%{public}08X)", errCode);
    if (g_sleSsapcHalCbks != NULL && g_sleSsapcHalCbks->OnSsapcFindStructDoneCb != NULL) {
        g_sleSsapcHalCbks->OnSsapcFindStructDoneCb(clientId, connectId, structureResult, errCode);
    }
}

static void OnSleHdiSsapcReadConformCallback(uint8_t clientId, uint16_t connectId, const ClientHandleValue *readData, SleHdiErrorCode errCode)
{
    if (g_sleSsapcHalCbks != NULL && g_sleSsapcHalCbks->OnSsapcRecvReadRespCb != NULL) {
        g_sleSsapcHalCbks->OnSsapcRecvReadRespCb(clientId, connectId, readData, errCode);
    }
}

static void OnSleHdiSsapcReadByUuidCompleteCallback(uint8_t clientId, uint16_t connectId, const ClientReadByUuidCmpRes *cmpResult, SleHdiErrorCode errCode)
{
    if (g_sleSsapcHalCbks != NULL && g_sleSsapcHalCbks->OnSsapcReadByUuidCb != NULL) {
        g_sleSsapcHalCbks->OnSsapcReadByUuidCb(clientId, connectId, cmpResult, errCode);
    }
}

static void OnSleHdiSsapcWriteConformCallback(uint8_t clientId, uint16_t connectId, const ClientWriteRes *writeResult, SleHdiErrorCode errCode)
{
    if (g_sleSsapcHalCbks != NULL && g_sleSsapcHalCbks->OnSsapcRecvWriteRespCb != NULL) {
        g_sleSsapcHalCbks->OnSsapcRecvWriteRespCb(clientId, connectId, writeResult, errCode);
    }
}

static void OnSleHdiSsapcExchangeInfoCallback(uint8_t clientId, uint16_t connectId, const SsapMtuInfo *param, SleHdiErrorCode errCode)
{
    SLE_LOGI("OnSleHdiSsapcExchangeInfoCallback connectId(%{public}d) mtu(%u) errCode(0x%{public}08X)", connectId, param->mtuSize, errCode);
    if (g_sleSsapcHalCbks != NULL && g_sleSsapcHalCbks->OnSsapcRecvExchangeInfoRespCb != NULL) {
        g_sleSsapcHalCbks->OnSsapcRecvExchangeInfoRespCb(clientId, connectId, param, errCode);
    }
}

static void OnSleHdiSsapcNotificationCallback(uint8_t clientId, uint16_t connectId, const ClientHandleValue *data, SleHdiErrorCode errCode)
{
    if (g_sleSsapcHalCbks != NULL && g_sleSsapcHalCbks->OnSsapcRecvNotificationCb != NULL) {
        g_sleSsapcHalCbks->OnSsapcRecvNotificationCb(clientId, connectId, data, errCode);
    }
}

static void OnSleHdiSsapcIndicationCallback(uint8_t clientId, uint16_t connectId, const ClientHandleValue *data, SleHdiErrorCode errCode)
{
    if (g_sleSsapcHalCbks != NULL && g_sleSsapcHalCbks->OnSsapcRecvIndicationCb != NULL) {
        g_sleSsapcHalCbks->OnSsapcRecvIndicationCb(clientId, connectId, data, errCode);
    }
}

SleHalErrorCode InitSleSsapcHal(void)
{
    SLE_LOGI("InitSleSsapcHal");
    SLE_ASSERT_AND_RETURN_RET_LOG(g_sleSsapcHalOpts == NULL, SLE_HAL_SUCCESS, "sleSsapcHal has been Inited");
    SleHalErrorCode ret = SLE_HAL_ERR_UNKNOWN;
    g_sleSsapcHalOpts = (SleSsapcHdiOpts*)malloc(sizeof(SleSsapcHdiOpts));
    ret = GetSleSsapcHalOpts(g_sleSsapcHalOpts);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "GetSleSsapcHalOpts fail(%{public}d)", ret);
    SLE_ASSERT_AND_RETURN_RET(g_sleSsapcHalOpts != NULL, SLE_HAL_ERR_COMMON);
    if (g_sleSsapcHdiCbks == NULL) {
        g_sleSsapcHdiCbks = (SleSsapcHdiCallbacks *)malloc(sizeof(SleSsapcHdiCallbacks));
        g_sleSsapcHdiCbks->OnStructureFoundCb = OnSleHdiSsapcFindStructureCallback;
        g_sleSsapcHdiCbks->OnPropertyFoundCb = OnSleHdiSsapcFindPropertyCallback;
        g_sleSsapcHdiCbks->OnFindStructureCmpCb = OnSleHdiSleHdiSsapcFindStructureCompleteCallback;
        g_sleSsapcHdiCbks->OnRecvReadResponseCb = OnSleHdiSsapcReadConformCallback;
        g_sleSsapcHdiCbks->OnRreadByUuidCmpCb = OnSleHdiSsapcReadByUuidCompleteCallback;
        g_sleSsapcHdiCbks->OnRecvWriteResponseCb = OnSleHdiSsapcWriteConformCallback;
        g_sleSsapcHdiCbks->OnExchangeInfoCb = OnSleHdiSsapcExchangeInfoCallback;
        g_sleSsapcHdiCbks->OnRecvNotificationCb = OnSleHdiSsapcNotificationCallback;
        g_sleSsapcHdiCbks->OnRecvIndicationCb = OnSleHdiSsapcIndicationCallback;
    }
    SLE_ASSERT_AND_RETURN_RET(g_sleSsapcHdiCbks != NULL, SLE_HAL_ERR_DRIVER_OR_SYSTEM);
    SleHdiErrorCode result = g_sleSsapcHalOpts->registerClientCbks(g_sleSsapcHdiCbks);
    ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "registerClientCbks fail(0x%{public}08X)", result);
    g_sleSsapcHalCbks = (SleSsapcHalCallbacks*)malloc(sizeof(SleSsapcHalCallbacks));
    return ret;
}

SleHalErrorCode DeinitSleSsapcHal(void)
{
    SLE_LOGI("DeinitSleSsapcHal");
    SLE_ASSERT_AND_RETURN_RET_LOG(g_sleSsapcHalOpts == NULL, SLE_HAL_SUCCESS, "sleSsapcHal has not been Inited");
    free(g_sleSsapcHalOpts);
    g_sleSsapcHalOpts = NULL;
    free(g_sleSsapcHdiCbks);
    g_sleSsapcHdiCbks = NULL;
    free(g_sleSsapcHalCbks);
    g_sleSsapcHalCbks = NULL;
    return SLE_HAL_SUCCESS;
}

SleHalErrorCode SleSsapcHalAddClient(const SleUuid *appUuid, uint8_t *clientId)
{
    SLE_LOGI("SleSsapcHalAddClient");
    SLE_ASSERT_AND_RETURN_RET(g_sleSsapcHalOpts != NULL, SLE_HAL_ERR_NOT_READY);
    SLE_ASSERT_AND_RETURN_RET(appUuid != NULL && clientId != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SleHdiErrorCode result = g_sleSsapcHalOpts->registerClient(appUuid, clientId);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "registerClient fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleSsapcHalRemoveClient(uint8_t clientId)
{
    SLE_LOGI("SleSsapcHalRemoveClient");
    SLE_ASSERT_AND_RETURN_RET(g_sleSsapcHalOpts != NULL, SLE_HAL_ERR_NOT_READY);
    SleHdiErrorCode result = g_sleSsapcHalOpts->unregisterClient(clientId);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "unregisterClient fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleSsapcHalFindStructure(uint8_t clientId, uint16_t connectId, const ClientFindStructure *paramFind)
{
    SLE_LOGI("SleSsapcHalFindStructure");
    SLE_ASSERT_AND_RETURN_RET(g_sleSsapcHalOpts != NULL, SLE_HAL_ERR_NOT_READY);
    SLE_ASSERT_AND_RETURN_RET(paramFind != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SleHdiErrorCode result = g_sleSsapcHalOpts->findStructure(clientId, connectId, paramFind);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "findStructure fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleSsapcHalReadReqByUuid(uint8_t clientId, uint16_t connectId, const ClientReadReqByUUID *paramRead)
{
    SLE_LOGD("SleSsapcHalReadReqByUuid");
    SLE_ASSERT_AND_RETURN_RET(g_sleSsapcHalOpts != NULL, SLE_HAL_ERR_NOT_READY);
    SLE_ASSERT_AND_RETURN_RET(paramRead != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SleHdiErrorCode result = g_sleSsapcHalOpts->readReqByUuid(clientId, connectId, paramRead);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "readReqByUuid fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleSsapcHalReadReq(uint8_t clientId, uint16_t connectId, uint16_t handle, SleSsapPropertyType type)
{
    SLE_LOGD("SleSsapcHalReadReq");
    SLE_ASSERT_AND_RETURN_RET(g_sleSsapcHalOpts != NULL, SLE_HAL_ERR_NOT_READY);
    SleHdiErrorCode result = g_sleSsapcHalOpts->readReq(clientId, connectId, handle, type);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "readReq fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleSsapcHalWriteReq(uint8_t clientId, uint16_t connectId, const ClientWriteParam *paramWrite)
{
#if 0
    SLE_LOGD("SleSsapcHalWriteReq");
#endif
    SLE_ASSERT_AND_RETURN_RET(g_sleSsapcHalOpts != NULL, SLE_HAL_ERR_NOT_READY);
    SLE_ASSERT_AND_RETURN_RET(paramWrite != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SleHdiErrorCode result = g_sleSsapcHalOpts->writeReq(clientId, connectId, paramWrite);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "writeReq fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleSsapcHalWriteCmd(uint8_t clientId, uint16_t connectId, const ClientWriteParam *paramWrite)
{
#if 0
    SLE_LOGD("SleSsapcHalWriteCmd");
#endif
    SLE_ASSERT_AND_RETURN_RET(g_sleSsapcHalOpts != NULL, SLE_HAL_ERR_NOT_READY);
    SLE_ASSERT_AND_RETURN_RET(paramWrite != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SleHdiErrorCode result = g_sleSsapcHalOpts->writeCmd(clientId, connectId, paramWrite);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "writeCmd fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleSsapcHalExchangeInfoReq(uint8_t clientId, uint16_t connectId,const SsapMtuInfo* paramExchange)
{
    SLE_LOGI("SleSsapcHalExchangeInfoReq");
    SLE_ASSERT_AND_RETURN_RET(g_sleSsapcHalOpts != NULL, SLE_HAL_ERR_NOT_READY);
    SLE_ASSERT_AND_RETURN_RET(paramExchange != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SleHdiErrorCode result = g_sleSsapcHalOpts->exchangeInfoReq(clientId, connectId, paramExchange);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "exchangeInfoReq fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleSsapcHalRegisterCallbacks(const SleSsapcHalCallbacks *callback)
{
    SLE_LOGD("SleSsapcHalRegisterCallbacks");
    SLE_ASSERT_AND_RETURN_RET(g_sleSsapcHalOpts != NULL, SLE_HAL_ERR_NOT_READY);
    SLE_ASSERT_AND_RETURN_RET(callback != NULL, SLE_HAL_ERR_INVALID_PARAM);
    memcpy(g_sleSsapcHalCbks, callback, sizeof(SleSsapcHalCallbacks));
    return SLE_HAL_SUCCESS;
}
